<template>
    <div class="star-sky-container">
        <canvas class="star-sky-content" :width="width" :height="height"></canvas>
    </div>
</template>

<script>

export default {
    name: "StarSky",
    data() {
        return {
            starColor: '#fff',//星星颜色
            starSize: 3,//星星大小
            starSpeed: 0.02,//星星速度
            decaySpeed: 0.01,//星星速度衰减
            overflowThreshold: 50,//溢出阈值
            starCount: 100,//星星数量
            stars: [],//星星数组
            width: 200,
            height: 200,
            pointerX: 0,
            pointerY: 0,
            //速度对象
            velocity: {
                tx: 0, //鼠标移动在X轴上的差值
                ty: 0, //鼠标移动在Y轴上的差值
            },
            ctx: null,
        }
    },
    methods: {
        //生成星星
        generateStars() {
            for (let i = 0; i < this.starCount; i++) {
                this.stars.push({
                    x: Math.random() * this.width,//初始X轴位置
                    y: Math.random() * this.height,//初始Y轴位置
                    sx: 0,//初始X轴加速度
                    sy: 0,//初始Y轴加速度
                });
            }
        },
        draw() {
            this.ctx.clearRect(0, 0, this.width, this.height);
            this.update();
            this.render();
            requestAnimationFrame(this.draw.bind(this));
        },
        //更新位置和速度
        update() {
            this.stars.forEach(star => {
                //模拟加速度衰减
                this.velocity.tx -= this.velocity.tx * this.decaySpeed;
                this.velocity.ty -= this.velocity.ty * this.decaySpeed;

                star.sx -= star.sx * this.decaySpeed;
                star.sy -= star.sy * this.decaySpeed;

                //星星移动与鼠标相反，所以-=
                star.sx -= this.velocity.tx * this.starSpeed;
                star.sy -= this.velocity.ty * this.starSpeed;

                star.x += star.sx;
                star.y += star.sy;

                //超出边界的放置在另一侧
                if (star.x < -this.overflowThreshold) {
                    star.x = this.width + this.overflowThreshold * Math.random();
                    star.y = this.height* Math.random();
                }
                if (star.x > this.width + this.overflowThreshold) {
                    star.x = -this.overflowThreshold * Math.random();
                    star.y = this.height* Math.random();
                }
                if (star.y < -this.overflowThreshold) {
                    star.x = this.width* Math.random();
                    star.y = this.height + this.overflowThreshold * Math.random();
                }
                if (star.y > this.height + this.overflowThreshold) {
                    star.x = this.width* Math.random();
                    star.y = -this.overflowThreshold * Math.random();
                }
            });
        },
        render() {
            this.stars.forEach(star => {
                this.ctx.beginPath();
                this.ctx.lineCap = "round";
                this.ctx.lineWidth = this.starSize * (Math.random() + 1);
                this.ctx.globalAlpha = 0.5 + 0.5 * Math.random();
                this.ctx.strokeStyle = this.starColor;

                this.ctx.beginPath();
                this.ctx.moveTo(star.x, star.y);

                //绘制拖尾
                let tailX = this.velocity.tx * 2;
                let tailY = this.velocity.ty * 2;

                this.ctx.lineTo(star.x + tailX, star.y + tailY);
                this.ctx.stroke();

            });
        },

        movePointer(event) {
            let x = event.clientX;
            let y = event.clientY;

            //鼠标刚移入DOM时差值设为零，防止撕裂画面
            if (this.pointerX) {
                this.velocity.tx = x - this.pointerX;
            } else {
                this.velocity.tx = 0;
            }

            if (this.pointerY) {
                this.velocity.ty = y - this.pointerY;
            } else {
                this.velocity.ty = 0
            }

            this.pointerX = x;
            this.pointerY = y;
        },
    },
    mounted() {
        const container = this.$el.parentElement.querySelector(".star-sky-container");
        const canvas = this.$el.querySelector(".star-sky-content");
        this.width = container.offsetWidth;
        this.height = container.offsetHeight;
        this.starCount = (this.width + this.height) / 16;
        this.ctx = canvas.getContext("2d");

        canvas.addEventListener("mousemove", this.movePointer);

        this.generateStars();
        this.draw();

    },
    beforeUnmount() {
        const canvas = this.$el.querySelector(".star-sky-content");
        canvas.removeEventListener("mousemove", this.movePointer);
    },
}
</script>

<style scoped>
.star-sky-container {
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    position: relative;
}

.star-sky-content {
    background-color: rgb(15 24 34);
}
</style>
